/*
 * sys_mgr.cpp
 *
 *  Created on: 2023年10月24日
 *      Author: Dylan.Gao
 */

#include <dm/export.hpp>

#define DM_API_OS_SYS DM_API_EXPORT

#include <dm/os/sys/sys_mgr.hpp>
#include <dm/os/shared_memory.hpp>
#include <dm/os/options.hpp>
#include <dm/scoped_ptr.hpp>

#include <dm/os/log/logger.hpp>

namespace dm{
namespace os{
namespace sys{

static const char* logModule = "CSysMgr.sys.os.dm";

enum{
#ifdef SYS_INFO_PROJECT_LEN
	MaxLenOfProject = SYS_INFO_PROJECT_LEN,
#else
	MaxLenOfProject = 128,
#endif

#ifdef SYS_HOST_NAME_LEN
	MaxLenOfHost = SYS_HOST_NAME_LEN,
#else
	MaxLenOfHost = 64,
#endif
};

struct SSysInfo{
	typedef dm::CFixdString<MaxLenOfProject> project_t;
	typedef dm::CFixdString<MaxLenOfHost> host_t;

	dm::CMagic::magic_t magic;	// 魔数
	dm::os::upgradable_mutex_t mutex;	// 互斥锁

	project_t project;	// 项目名称
	host_t host;	// 主机名称
	dm::CTimeStamp::us_t usRefresh;	// 系统刷新间隔

	CSysMgr::EState state;	// 系统状态

	pid_t pid;	// 系统进程ID

	dm::CRunTimeStamp rtsState;		// 状态更新时刻
	dm::CRunTimeStamp rtsRefresh;	// 刷新时刻
	dm::CRunTimeStamp rtsNext;		// 下次刷新时刻，如果当前已经超过未刷新，说明系统未运行

	dm::CRunTimeStamp rtsFirst;	// 第一次运行时刻
	dm::CRunTimeStamp rtsThis;	// 本次运行时刻
	dm::CRunTimeStamp rtsExit;	// 退回时刻
};

static dm::TScopedPtr<boost::interprocess::mapped_region> MappedRegion;
static volatile SSysInfo* PInfo = nullptr;

/**
 * 状态描述信息
 */
static const char* StateStrings[CSysMgr::SMax] = {
		"未初始化","正在启动","正在运行","退出","正在重启","系统待机"
};

CSysMgr::CSysMgr(){
	log().debug(THISMODULE "创建对象");
	dm::os::CUnrestrictedPermissions p;
	MappedRegion = dm::os::getSharedMemory<SSysInfo>(logModule,p, &PInfo );

	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		log().error(THISMODULE "获取共享内存失败");
	}else{
		boost::interprocess::upgradable_lock<upgradable_mutex_t> upgradableLock(pInfo->mutex);
		if( pInfo->state==SUninit ){	// 未初始化
			dm::env::COptions options;
			boost::interprocess::scoped_lock<upgradable_mutex_t> scopedLock(boost::move(upgradableLock));

			pInfo->project = options.getString("Name", "DM2016系统", "System");
			pInfo->usRefresh = options.getInt("MsRefresh", 1000, "System")*1000l;
		}
	}
}

CSysMgr& CSysMgr::ins(){
	static CSysMgr i;
	return i;
}

/**
 * 状态转换成描述信息
 */
const char* CSysMgr::state2string( EState state ){
	if( state<0 || state>=SMax )
		return nullptr;
	return StateStrings[state];
}

/**
 * 更新任务状态
 * 如果任务已经被其他进程启动，则失败
 * @param pid
 * @param state 返回当前系统状态
 * @param rtsNow
 * @return
 */
bool CSysMgr::update( const pid_t& pid,EState& state,const dm::CRunTimeStamp& rtsNow ){
	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		return false;
	}else{
		boost::interprocess::upgradable_lock<upgradable_mutex_t> upgradableLock(pInfo->mutex);

		if( pInfo->pid!=pid ){	// 判断其他进程是否启动
			if( pInfo->pid>0 && pInfo->rtsNext>=rtsNow ){
				state = pInfo->state;
				log().info(THISMODULE "系统进程已经运行[%s]",state2string(state));
				return false;
			}
		}

		boost::interprocess::scoped_lock<upgradable_mutex_t> scopedLock(boost::move(upgradableLock));

		if( pInfo->pid!=pid ){	// 原来的数据无效
			pInfo->pid = pid;
			pInfo->rtsThis = rtsNow;
			if( pInfo->rtsFirst.isInv() )
				pInfo->rtsFirst = rtsNow;
		}else{	// 守护进程没变
			if( pInfo->state==SExit ){
				state = pInfo->state;
				return false;
			}
		}

		if( pInfo->state!=state ){
			pInfo->state = state;
			pInfo->rtsState = rtsNow;
		}

		pInfo->rtsRefresh = rtsNow;
		if( state==SExit )
			pInfo->rtsExit = rtsNow;

		pInfo->rtsNext = rtsNow;
		pInfo->rtsNext.addMsecs(pInfo->usRefresh);

		return true;
	}
}

bool CSysMgr::set( EState state,const dm::CRunTimeStamp& rtsNow ){
	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		return false;
	}else{
		boost::interprocess::scoped_lock<upgradable_mutex_t> scopedLock(pInfo->mutex);
		if( pInfo->state!=state ){
			pInfo->state = state;
			pInfo->rtsState = rtsNow;
		}

		return true;
	}
}

CSysMgr::EState CSysMgr::getState(){
	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		return SMax;
	}else{
		boost::interprocess::sharable_lock<upgradable_mutex_t> sharedLock(pInfo->mutex);
		return pInfo->state;
	}
}

dm::CRunTimeStamp CSysMgr::getRtsState(){
	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		return dm::CRunTimeStamp();
	}else{
		boost::interprocess::sharable_lock<upgradable_mutex_t> sharedLock(pInfo->mutex);
		return pInfo->rtsState;
	}
}

dm::CRunTimeStamp CSysMgr::getRtsRefresh(){
	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		return dm::CRunTimeStamp();
	}else{
		boost::interprocess::sharable_lock<upgradable_mutex_t> sharedLock(pInfo->mutex);
		return pInfo->rtsRefresh;
	}
}

dm::CRunTimeStamp CSysMgr::getRtsNext(){
	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		return dm::CRunTimeStamp();
	}else{
		boost::interprocess::sharable_lock<upgradable_mutex_t> sharedLock(pInfo->mutex);
		return pInfo->rtsNext;
	}
}

dm::CRunTimeStamp CSysMgr::getRtsFirst(){
	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		return dm::CRunTimeStamp();
	}else{
		boost::interprocess::sharable_lock<upgradable_mutex_t> sharedLock(pInfo->mutex);
		return pInfo->rtsFirst;
	}
}

dm::CRunTimeStamp CSysMgr::getRtsThis(){
	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		return dm::CRunTimeStamp();
	}else{
		boost::interprocess::sharable_lock<upgradable_mutex_t> sharedLock(pInfo->mutex);
		return pInfo->rtsThis;
	}
}

dm::CRunTimeStamp CSysMgr::getRtsExit(){
	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		return dm::CRunTimeStamp();
	}else{
		boost::interprocess::sharable_lock<upgradable_mutex_t> sharedLock(pInfo->mutex);
		return pInfo->rtsExit;
	}
}

bool CSysMgr::get( EState* pState,dm::CRunTimeStamp* pRtsState,dm::CRunTimeStamp* pRtsRefresh,dm::CRunTimeStamp* pRtsNext,dm::CRunTimeStamp* pRtsFirst,dm::CRunTimeStamp* pRtsThis,dm::CRunTimeStamp* pRtsExit ){
	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		return false;
	}else{
		boost::interprocess::sharable_lock<upgradable_mutex_t> sharedLock(pInfo->mutex);
		if( pState )
			*pState = pInfo->state;
		if( pRtsState )
			*pRtsState = pInfo->rtsState;
		if( pRtsRefresh )
			*pRtsRefresh = pInfo->rtsRefresh;
		if( pRtsNext )
			*pRtsNext = pInfo->rtsNext;
		if( pRtsThis )
			*pRtsThis = pInfo->rtsThis;
		if( pRtsExit )
			*pRtsExit = pInfo->rtsExit;

		return true;
	}
}

/**
 * 系统当前是否可以运行
 * @param rtsNow
 * @return
 */
bool CSysMgr::ifCanRun( const dm::CRunTimeStamp& rtsNow ){
	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		return false;
	}else{
		boost::interprocess::sharable_lock<upgradable_mutex_t> sharedLock(pInfo->mutex);
		return pInfo->pid>0 && (pInfo->state==SStarting||pInfo->state==SRunning) && rtsNow<=pInfo->rtsNext;
	}
}

bool CSysMgr::ifExit( const dm::CRunTimeStamp& rtsNow ){
	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		return false;
	}else{
		boost::interprocess::sharable_lock<upgradable_mutex_t> sharedLock(pInfo->mutex);
		return pInfo->pid>0 && (pInfo->state==SExit) && rtsNow<=pInfo->rtsNext;
	}
}

bool CSysMgr::reload( const dm::CRunTimeStamp& rtsNow ){
	SSysInfo* pInfo = const_cast<SSysInfo*>(PInfo);
	if( !pInfo ){
		return false;
	}else{
		dm::env::COptions options;

		boost::interprocess::scoped_lock<upgradable_mutex_t> scopedLock(pInfo->mutex);
		pInfo->project = options.getString("Name", "DM2016系统", "System");
		pInfo->usRefresh = options.getInt("MsRefresh", 1000, "System")*1000l;

		return true;
	}
}

}
}
}
